package com.pacvue.configuration;

import java.time.Duration;

import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.pacvue.handler.DefaultRateLimitExceptionHandler;
import com.pacvue.handler.LocalRateLimiterAcquireTokenHandler;
import com.pacvue.handler.RateLimitExceptionHandler;
import com.pacvue.handler.RedisRateLimiterAcquireTokenHandler;
import com.pacvue.properties.RateLimiterProperties;

import io.lettuce.core.ClientOptions;
import io.lettuce.core.ReadFrom;
import io.lettuce.core.resource.ClientResources;
import io.lettuce.core.resource.DefaultClientResources;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Configuration
@RequiredArgsConstructor
@ConditionalOnProperty(prefix = "rate-limiter", name = "enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(RateLimiterProperties.class)
public class RateLimiterAutoConfiguration {

    /**
     * 初始化限流异常处理类， 默认使用DefaultRateLimitExceptionHandler
     */
    @Bean
    @ConditionalOnMissingBean(RateLimitExceptionHandler.class)
    public RateLimitExceptionHandler rateLimitExceptionHandler() {
        return new DefaultRateLimitExceptionHandler();
    }

    /**
     * 初始化本地限流处理器
     */
    @Bean
    @ConditionalOnProperty(prefix = "rate-limiter", name = "handler-type", havingValue = "local", matchIfMissing = true)
    public LocalRateLimiterAcquireTokenHandler localRateLimiterAcquireTokenHandler()  {
        log.info("初始化本地限流处理器");
        return new LocalRateLimiterAcquireTokenHandler();
    }

    /**
     * 初始化Redis限流处理器
     */
    @Bean
    @ConditionalOnProperty(prefix = "rate-limiter", name = "handler-type", havingValue = "redis")
    public RedisRateLimiterAcquireTokenHandler redisRateLimiterAcquireTokenHandler(RateLimiterProperties properties)  {
        log.info("初始化Redis限流处理器");
        RateLimiterProperties.RedisConfig redis = properties.getRedis();
        
        if (redis == null || redis.getHost() == null) {
            throw new IllegalArgumentException("Redis限流器需要配置redis.host属性");
        }
        
        // 创建 RedisStandaloneConfiguration
        RedisStandaloneConfiguration redisConfig = new RedisStandaloneConfiguration();
        redisConfig.setHostName(redis.getHost());
        redisConfig.setPort(redis.getPort());
        redisConfig.setDatabase(redis.getDatabase());
        if (redis.getPassword() != null && !redis.getPassword().isEmpty()) {
            redisConfig.setPassword(redis.getPassword());
        }

        // 优化客户端资源配置
        ClientResources clientResources = DefaultClientResources.builder()
                .ioThreadPoolSize(4)  // IO线程池大小
                .computationThreadPoolSize(4)  // 计算线程池大小
                .build();

        // 优化客户端选项
        ClientOptions clientOptions = ClientOptions.builder()
                .autoReconnect(true)  // 自动重连
                .disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS)  // 断开时拒绝命令
                .build();

        // 创建 LettuceClientConfiguration 配置连接池
        LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
                .clientOptions(clientOptions)
                .clientResources(clientResources)
                .commandTimeout(Duration.ofSeconds(redis.getCommandTimeout()))
                .shutdownTimeout(Duration.ofSeconds(2))
                .readFrom(ReadFrom.MASTER_PREFERRED)  // 优先从主节点读取
                .build();

        // 创建 RedisConnectionFactory
        LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisConfig, clientConfig);
        lettuceConnectionFactory.afterPropertiesSet();

        // 创建 RedisTemplate
        RedisTemplate<String, String> template = new RedisTemplate<>();
        template.setConnectionFactory(lettuceConnectionFactory);
        // 设置 Key 和 Value 序列化，确保使用 String
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new StringRedisSerializer());
        template.afterPropertiesSet();

        // 创建 执行脚本
        DefaultRedisScript<Long> script = new DefaultRedisScript<>();
        script.setLocation(new ClassPathResource("script/rate_limiter.lua"));
        script.setResultType(Long.class);
        
        log.info("Redis限流处理器初始化完成 - host: {}, port: {}, database: {}", 
                redis.getHost(), redis.getPort(), redis.getDatabase());
        
        return new RedisRateLimiterAcquireTokenHandler(template, script);
    }

}
